package com.zh.springcloud.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import java.util.ArrayList;
import java.util.List;

/**
 * @Description: 配置授权服务器
 * @ClassName AuthorizationServerConfig
 * @date: 2021.10.26 20:14
 * @Author: zhanghang
 */
@Configuration
@EnableAuthorizationServer // 开启授权服务器
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

	@Autowired
	private PasswordEncoder passwordEncoder;

	@Autowired
	private AuthenticationManager authenticationManager;

	@Autowired
	private MyUserDetailsService myUserDetailsService;

	@Autowired
	@Qualifier("jwtTokenStore")
	private TokenStore jwtTokenStore;

	@Autowired
	private JwtAccessTokenConverter accessTokenConverter;

	@Autowired
	private JwtTokenEnhancer jwtTokenEnhancer;


	/**
	 * description: 用来配置客户端详情服务（ClientDetailsService），
	 * 客户端详情信息在这里进行初始化，你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息；
	 * date: 2021年-10月-27日 9:37
	 * author: zhanghang
	 *
	 * @param clients
	 * @return void
	 */
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		// 使用内存的方式配置
		clients.inMemory()
				// 配置client id
				.withClient("clientId")
				// 配置秘钥,秘钥也需要加密
				.secret(passwordEncoder.encode("112233"))
				// 设置token 的失效时间，单位为秒, 默认有效期为24小时
				.accessTokenValiditySeconds(60)
				// 设置刷新 token 的过期时间
				.refreshTokenValiditySeconds(120)
				// 配置重定向的地址
//				.redirectUris("http://www.baidu.com")
				// 重定向到客户端地址
				.redirectUris("http://lcoalhost:8082/login")
				// 配置范围
				.scopes("all")
				// 自动授权
				.autoApprove(true)
				/**
				 * 配置授权的类型
				 *authorization_code: 授权码模式
				 * password: 密码模式
				 * refresh_token: 刷新token
				 */
				.authorizedGrantTypes("authorization_code","password","refresh_token");
	}

	/**
	 * description: 用来配置授权（authorization）以及令牌（token）的访问端点和令牌服务(token services)，
	 * 还有token的存储方式(tokenStore)；
	 * date: 2021年-10月-29日 15:47
	 * author: zhanghang
	 *
	 * @param endpoints
	 * @return void
	 */
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		// 设置jwt增强内容
		TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
		List<TokenEnhancer> delegates = new ArrayList<>();
		delegates.add(jwtTokenEnhancer);
		delegates.add(accessTokenConverter);
		tokenEnhancerChain.setTokenEnhancers(delegates);
		// 配置认证管理器
		endpoints.authenticationManager(authenticationManager)
				.userDetailsService(myUserDetailsService)
				// 使用jwt 来保存token
				.tokenStore(jwtTokenStore)
				// accessToken 转换成JWT token
				.accessTokenConverter(accessTokenConverter)
				// 设置jwt 增强扩展信息
				.tokenEnhancer(tokenEnhancerChain);
	}

	/**
	 * description: configure
	 * date: 2021年-11月-28日 21:40
	 * author: zhanghang
	 *
	 * @param security
	 * @return void
	 */
	@Override
	public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
		// 获取秘钥必须要身份认证，单点登录必须要配置
		security.tokenKeyAccess("isAuthenticated()");
	}
}
